package dnet

import (
	"dgo/goutils/utils"
	"fmt"
	"sync/atomic"
	"time"
)

/*
**
注意32位下 对齐
*/
type DNetInfo struct {
	online_cnt     int32
	max_online_cnt int32
	recvbytes      uint64
	sendbytes      uint64
	sendIO_cnt     uint64
	recvIO_cnt     uint64
	dis_cnt        uint64
	con_cnt        uint64

	last_sendio_cnt      uint64
	last_send_bytes      uint64
	last_recvio_cnt      uint64
	last_recv_bytes      uint64
	last_speed_recvbytes uint64
	last_speed_sendbytes uint64
	last_speed_sendio    uint64
	last_speed_recvio    uint64

	last_calc_t   time.Time
	calc_task_dna int

	statusflag int

	ID string
}

func (this *DNetInfo) SetEnable(enable bool) {
	if enable {
		this.statusflag = 0
	} else {
		this.statusflag = -1
	}
}

func (this *DNetInfo) ResetInfo() {
	this.online_cnt = 0
	this.max_online_cnt = 0
	this.dis_cnt = 0
	this.con_cnt = 0
	this.sendbytes = 0
	this.sendIO_cnt = 0
	this.recvbytes = 0
	this.recvIO_cnt = 0
	this.last_recv_bytes = 0
	this.last_recvio_cnt = 0
	this.last_sendio_cnt = 0
	this.last_send_bytes = 0
	this.last_calc_t = utils.ZeroTime
}

func (this *DNetInfo) CheckStartSpeedTask() {
	if utils.TimeIsUnixZero(this.last_calc_t) {
		if len(this.ID) == 0 {
			this.ID = utils.RandHexString(24)
		}
		dna := this.calc_task_dna
		utils.AddTaskFxiedInterval(this.ID, time.Second*2, func() bool {
			this.calcuSpeed()
			return dna == this.calc_task_dna
		})
	}
}

func (this *DNetInfo) StopSpeedTask() {
	if !utils.TimeIsUnixZero(this.last_calc_t) {
		this.calc_task_dna++
		this.last_calc_t = utils.ZeroTime
	}

}

func (this *DNetInfo) GetInfoCbDetail(cb func(k string, v interface{})) {

	cb("online", this.online_cnt)
	cb("max_online_cnt", this.max_online_cnt)
	cb("dis_cnt", this.dis_cnt)
	cb("con_cnt", this.con_cnt)
	cb("recv_bytes", this.recvbytes)
	cb("send_bytes", this.sendbytes)
	cb("speed_recvbytes", this.last_speed_recvbytes)
	cb("speed_sendbytes", this.last_speed_sendbytes)
	cb("recv_io", this.recvIO_cnt)
	cb("send_io", this.sendIO_cnt)
	cb("speed_recvio", this.last_speed_recvio)
	cb("speed_sendio", this.last_speed_sendio)
}

func (this *DNetInfo) GetInfoCb(cb func(k string, v interface{})) {

	cb("online", this.online_cnt)
	cb("max_online_cnt", this.max_online_cnt)
	cb("dis_cnt", this.dis_cnt)
	cb("con_cnt", this.con_cnt)
	cb("recvinfo", fmt.Sprintf("%s(s) %s", utils.HumanFilesizeU(this.last_speed_recvbytes),
		utils.HumanFilesizeU(this.recvbytes)))
	cb("sendinfo", fmt.Sprintf("%s(s) %s", utils.HumanFilesizeU(this.last_speed_sendbytes),
		utils.HumanFilesizeU(this.sendbytes)))

	cb("recvio", fmt.Sprintf("%d(s) %d", this.last_speed_recvio, this.recvIO_cnt))
	cb("sendio", fmt.Sprintf("%d(s) %d", this.last_speed_sendio, this.sendIO_cnt))
}

func (this *DNetInfo) calcuSpeed() {
	if !utils.TimeIsUnixZero(this.last_calc_t) {
		t1 := time.Now().Sub(this.last_calc_t).Seconds()
		if t1 > 0 {
			v := this.sendbytes - this.last_send_bytes
			speed := uint64(float64(v) / t1)
			this.last_speed_sendbytes = speed

			{
				v := this.sendIO_cnt - this.last_sendio_cnt
				speed := uint64(float64(v) / t1)
				this.last_speed_sendio = speed
			}

			{
				v := this.recvbytes - this.last_recv_bytes
				speed := uint64(float64(v) / t1)
				this.last_speed_recvbytes = speed
			}

			{
				v := this.recvIO_cnt - this.last_recvio_cnt
				speed := uint64(float64(v) / t1)
				this.last_speed_recvio = speed
			}
		}
	}

	this.last_calc_t = time.Now()
	this.last_sendio_cnt = this.sendIO_cnt
	this.last_send_bytes = this.sendbytes
	this.last_recvio_cnt = this.recvIO_cnt
	this.last_recv_bytes = this.recvbytes
}

func (this *DNetInfo) DoConnect() {
	if this.statusflag == -1 {
		return
	}
	atomic.AddUint64(&this.con_cnt, 1)
	v := atomic.AddInt32(&this.online_cnt, 1)
	if v > this.max_online_cnt {
		this.max_online_cnt = v
	}
}

func (this *DNetInfo) DoDisconnect() {
	if this.statusflag == -1 {
		return
	}
	atomic.AddUint64(&this.dis_cnt, 1)
	atomic.AddInt32(&this.online_cnt, -1)
}

func (this *DNetInfo) DoRecvBytes(n uint64) {
	if this.statusflag == -1 {
		return
	}
	atomic.AddUint64(&this.recvbytes, n)
	atomic.AddUint64(&this.recvIO_cnt, 1)
}

func (this *DNetInfo) DoSendBytes(n uint64) {
	if this.statusflag == -1 {
		return
	}
	atomic.AddUint64(&this.sendbytes, n)
	atomic.AddUint64(&this.sendIO_cnt, 1)
}
